Add mypy/flake8/pylint CI workflows, fix all type errors and lint errors - #1314
Conversation
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Updated mypy installation steps to install mypy separately.
|
@copilot Fix mypy errors and any errors until reaching 0 errors. See recent run log with mypy errors from |
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Fixed all 11 errors in commit
|
pythainlp/braille/core.py contains a Union type using We want all the code to be compatible fully with Python 3.9, including at the runtime. The use of
Add pylint and flake8 to .github/workflows/lint.yml
|
Co-authored-by: bact <128572+bact@users.noreply.github.com>
…eck type: ignore comments Co-authored-by: bact <128572+bact@users.noreply.github.com>
…ignore comments Co-authored-by: bact <128572+bact@users.noreply.github.com>
All three tasks addressed across commits 1.
2. 3.
All |
|
@copilot try to fix all these and remove the flake8 exception Then run mypy, flake8, pylint, ruff again and reevaluate any remaining type ignore comments; fix all the errors |
…ores from .flake8 Co-authored-by: bact <128572+bact@users.noreply.github.com>
... Fixed in commit
All four linters now pass at 0 errors with no suppressions for these issues:
|
|
@copilot With flake8-type-checking, reevaluate if we still need these flake8 exceptions? Then run mypy, flake8, pylint, ruff again and reevaluate any remaining type ignore comments; fix all the errors. We are now preparing for the release, so finishing up, polishing up. Fix remaining formatting, trailing whitespace, double blank lines at the end of files, etc. |
Co-authored-by: bact <128572+bact@users.noreply.github.com>
Move 37 type-only imports across 27 files into if TYPE_CHECKING: blocks to satisfy flake8-type-checking rules TC001, TC002, and TC003. All affected files already have 'from __future__ import annotations', so annotations are lazily evaluated strings at runtime. These imports are only used in type annotations and are not needed at runtime. Files with existing TYPE_CHECKING block (imports merged in): - pythainlp/corpus/core.py - pythainlp/phayathaibert/core.py - pythainlp/summarize/keybert.py - pythainlp/ulmfit/core.py Files with new TYPE_CHECKING block added: - pythainlp/augment/wordnet.py - pythainlp/corpus/util.py - pythainlp/corpus/wordnet.py - pythainlp/spell/pn.py - pythainlp/summarize/core.py - pythainlp/tag/_tag_perceptron.py - pythainlp/tag/crfchunk.py - pythainlp/tokenize/_utils.py - pythainlp/tokenize/core.py - pythainlp/tokenize/longest.py - pythainlp/tokenize/multi_cut.py - pythainlp/tokenize/nercut.py - pythainlp/tokenize/newmm.py - pythainlp/tokenize/pyicu.py - pythainlp/tokenize/tcc.py - pythainlp/tokenize/tcc_p.py - pythainlp/tools/path.py - pythainlp/transliterate/lookup.py - pythainlp/ulmfit/preprocess.py - pythainlp/ulmfit/tokenizer.py - pythainlp/util/collate.py - pythainlp/util/remove_trailing_repeat_consonants.py - pythainlp/util/strftime.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|



What do these changes do
Adds
.github/workflows/mypy.yml— a CI workflow that runsmypy pythainlpon every PR and push todev. Fixes all mypy errors across 7 source files, bringing the codebase to 0 mypy errors. Also enforces Python 3.9 runtime-compatible type annotations throughout, addsflake8andflake8-type-checkingsupport with a.flake8config file, addspylintto dev dependencies, fixes allX | Yunion syntax toUnion[X, Y]/Optional[X], fixes all TC006cast()annotation errors, fixes all TC005 emptyTYPE_CHECKINGblock errors, fixes all F401 false positives onTYPE_CHECKINGimports, fixes all bare-except (E722) and missing blank line (E302) issues, and moves all type-only imports intoTYPE_CHECKINGblocks (TC001/TC002/TC003) across 27 files.What was wrong
No automated static type checking or comprehensive linting existed in CI. Type regressions could be merged undetected despite
[tool.mypy]config andmypyalready being in[dev]dependencies. Several pre-existing issues existed in the codebase:pythainlp/lm/qwen3.py–tokenizer.decode()(from transformers) typed asAny, but the functions declaredstras return typepythainlp/tools/path.py– stale# type: ignore[no-redef]on theimportlib_resourcesimport;from sys import version_infoprevented mypy from narrowing the version guard's dead branchpythainlp/transliterate/core.py– wrong module path (pythainlp.translate.umt5_thaig2pinstead ofpythainlp.transliterate.umt5_thaig2p);# type: ignore[no-redef]did not coverimport-not-foundpythainlp/__init__.py– stale# type: ignoreon__version__pythainlp/tokenize/nlpo3.py–nlpo3missing from the mypyignore_missing_importsoverride listpythainlp/braille/core.pyandpythainlp/benchmarks/metrics.py–X | Yunion syntax used in type annotations, which is not supported at runtime in Python 3.9pythainlp/braille/core.py– union type caused__setitem__,join, and dict-index mypy errorspythainlp/benchmarks/metrics.py– list comprehension type mismatch; incorrectdict[str, float]return typecast(Type, x)used instead ofcast("Type", x)(TC006)if TYPE_CHECKING:blocks (TC005)TYPE_CHECKINGimports caused by dual-import pattern or incorrect# noqaplacement on multi-line importspythainlp/benchmarks/word_tokenization.py,pythainlp/khavee/core.py(×2),pythainlp/spell/wanchanberta_thai_grammarly.py– bareexcept:clauses (E722)pythainlp/chat/core.py– missing blank line before class definition (E302)TYPE_CHECKINGblocks (TC001/TC002/TC003), silently suppressed rather than properly fixedHow this fixes it
New workflow (
.github/workflows/mypy.yml):push/pull_requesttodev; skips doc-only changes (.cff,.json,.md,.rst,.txt,docs/**). YAML files are not excluded so workflow changes also trigger the check.python_version = "3.9"in[tool.mypy].pip install ".[dev]"(mypy already declared asmypy>=1.19.1).mypy pythainlpwith no extra flags; delegates all config to the existing[tool.mypy]block inpyproject.toml.lint.ymlto cancel redundant runs.permissions: contents: read(least-privilegeGITHUB_TOKEN).Python 3.9 runtime-compatible type annotations:
pythainlp/braille/core.py–list[list[str]] | list[str] | str→Union[list[list[str]], list[str], str];:type:docstring updated toUnion[...]pythainlp/benchmarks/metrics.py–list[str] | None→Optional[list[str]]; docstring:rtype:and:param:entries updatedmypy error fixes:
pythainlp/__init__.py– removed stale# type: ignoreon__version__pythainlp/tools/path.py– changedfrom sys import version_infotoimport sysandsys.version_infoso mypy correctly eliminates the dead branch; removed the now-unnecessary# type: ignore[no-redef]pythainlp/transliterate/core.py– corrected module path frompythainlp.translate.umt5_thaig2ptopythainlp.transliterate.umt5_thaig2p(module exists there); removed now-unneeded# type: ignore[import-not-found, no-redef]pyproject.toml– addednlpo3.*,importlib_resources, andimportlib_resources.*to the mypyignore_missing_importsoverridepythainlp/lm/qwen3.py– wrapped bothtokenizer.decode()calls instr()to satisfy thestrreturn typepythainlp/braille/core.py– used a typedlist[list[str]]local variable (withenumerate()) to avoid the union__setitem__error; addedcast("list[str]", self.data)in single-item branches forjoinand index operationspythainlp/benchmarks/metrics.py– addedcast("list[str]", references)in the list comprehension; corrected return type fromdict[str, float]todict[str, Union[float, list[float]]]flake8 + flake8-type-checking + pylint:
flake8>=7.0.0,flake8-type-checking>=3.2.0, andpylint>=4.0.0to dev dependencies inpyproject.toml.flake8config: retains E203/E402/E501/W503/F811 suppressions (all still needed — verified 73 real violations exist); noper-file-ignoresneededcast(Type, x)→cast("Type", x)across 16 filesif TYPE_CHECKING:blocks fromparse/ud_goeswith.pyandtransliterate/wunsen.py# noqa: F401to the openingfromline of multi-line TYPE_CHECKING imports (nlpo3.py,transformers_ud.py,phayathaibert/core.py); added# noqa: F401where the dual-import pattern caused spurious F401s (zh_th.py,thai_nner.py)except:→except Exception:) inbenchmarks/word_tokenization.py,khavee/core.py(×2), andspell/wanchanberta_thai_grammarly.pychat/core.pyruff formatto 14 files that needed formattingTC001/TC002/TC003 — properly fixed across 27 files:
if TYPE_CHECKING:blocks rather than suppressedfrom __future__ import annotations, making this safe — annotations are lazily evaluated strings at runtimecollections.abctypes (Callable,Collection,Generator,Iterable,ItemsView,Iterator,Sequence),contextlib.AbstractContextManager,datetime.datetime,http.client.HTTPMessage/HTTPResponse,os.PathLike,types,nltk.corpus.reader.wordnet.Synset, andpythainlp.util.TrieAll
# type: ignorecomments verified: every comment retains a specific error code;warn_unused_ignores = true(already configured) confirms all are still active — mypy: 0 errors, ruff: 0 errors, flake8: 0 errors, CodeQL: 0 alerts.Your checklist for this pull request
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.